Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | 'use client';
import { useState } from 'react';
import Link from 'next/link';
import Image from 'next/image';
import { useTranslation } from 'react-i18next';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Mail, ArrowLeft, Loader2, CheckCircle } from 'lucide-react';
import { API_ENDPOINTS } from '@/constants/api';
export default function ForgotPasswordPage() {
const { t } = useTranslation();
const [email, setEmail] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const [submitted, setSubmitted] = useState(false);
const [error, setError] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsSubmitting(true);
setError('');
try {
const response = await fetch(API_ENDPOINTS.AUTH.FORGOT_PASSWORD, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email })});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || t('auth.forgotPasswordFlow.failedToSendResetEmail'));
}
setSubmitted(true);
} catch (err: any) {
setError(err.message || t('auth.forgotPasswordFlow.genericError'));
} finally {
setIsSubmitting(false);
}
};
if (submitted) {
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 p-4">
<div className="w-full max-w-md">
<div className="bg-slate-900/50 backdrop-blur-xl rounded-3xl border border-slate-700/50 p-8 shadow-2xl text-center">
<div className="w-16 h-16 bg-green-500/20 rounded-full flex items-center justify-center mx-auto mb-6">
<CheckCircle className="w-8 h-8 text-green-400" />
</div>
<h1 className="text-2xl font-bold text-white mb-4">{t('auth.forgotPasswordFlow.checkYourEmailTitle')}</h1>
<p className="text-slate-400 mb-6">
{t('auth.forgotPasswordFlow.checkYourEmailDescription')}
</p>
<Link href="/login">
<Button variant="outline" className="w-full">
<ArrowLeft className="w-4 h-4 mr-2" />
{t('auth.forgotPasswordFlow.backToLogin')}
</Button>
</Link>
</div>
</div>
</div>
);
}
return (
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 p-4">
<div className="w-full max-w-md">
<div className="bg-slate-900/50 backdrop-blur-xl rounded-3xl border border-slate-700/50 p-8 shadow-2xl">
{/* Logo */}
<div className="flex justify-center mb-8">
<div className="relative">
<div className="absolute inset-0 bg-gradient-to-r from-cyan-400 to-purple-600 rounded-2xl blur-xl opacity-75 animate-pulse"></div>
<div className="relative bg-slate-800/80 backdrop-blur-md p-4 rounded-2xl">
<Image
src="/logo.png"
alt={t('common.title')}
width={48}
height={48}
className="object-contain"
priority
/>
</div>
</div>
</div>
{/* Header */}
<div className="text-center mb-8">
<h1 className="text-2xl font-bold text-white mb-2">
{t('auth.forgotPasswordFlow.forgotPasswordTitle')}
</h1>
<p className="text-slate-400">
{t('auth.forgotPasswordFlow.forgotPasswordDescription')}
</p>
</div>
{/* Error Message */}
{error && (
<div className="mb-6 p-4 bg-red-500/10 border border-red-500/30 rounded-xl">
<p className="text-red-400 text-sm text-center">{error}</p>
</div>
)}
{/* Form */}
<form onSubmit={handleSubmit} className="space-y-6">
<div className="space-y-2">
<label className="text-sm font-medium text-slate-300">
{t('auth.forgotPasswordFlow.emailAddressLabel')}
</label>
<div className="relative">
<Mail className="absolute left-4 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-500" />
<Input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder={t('profile.emailPlaceholder')}
required
className="pl-12 h-14 bg-slate-800/50 border-slate-700/50 text-white placeholder:text-slate-500 rounded-xl focus:ring-2 focus:ring-indigo-500/50"
/>
</div>
</div>
<Button
type="submit"
disabled={isSubmitting || !email}
className="w-full h-14 bg-gradient-to-r from-indigo-600 to-purple-600 hover:from-indigo-500 hover:to-purple-500 text-white font-semibold rounded-xl transition-all duration-300 shadow-lg shadow-indigo-500/25"
>
{isSubmitting ? (
<>
<Loader2 className="w-5 h-5 mr-2 animate-spin" />
{t('auth.forgotPasswordFlow.sending')}
</>
) : (
t('auth.forgotPasswordFlow.sendResetLink')
)}
</Button>
</form>
{/* Back to Login */}
<div className="mt-6 text-center">
<Link
href="/login"
className="text-indigo-400 hover:text-indigo-300 text-sm font-medium flex items-center justify-center gap-2"
>
<ArrowLeft className="w-4 h-4" />
{t('auth.forgotPasswordFlow.backToLogin')}
</Link>
</div>
</div>
</div>
</div>
);
}
|